package com.yuandian.management.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuandian.api.management.entity.ConfAgentIp;
import com.yuandian.api.management.entity.ConfAgentStatusInfo;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.management.enums.AgentStatus;
import com.yuandian.management.enums.StatusEnum;
import com.yuandian.management.enums.WrongStatusEnum;
import com.yuandian.management.mapper.ConfAgentStatusInfoMapper;
import com.yuandian.management.service.ConfAgentIpService;
import com.yuandian.management.service.ConfAgentStatusInfoService;
import com.yuandian.management.utils.DateTool;
import com.yuandian.management.utils.IpUtils;
import com.yuandian.management.vo.*;
import com.yuandian.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 迁移至 BPM3.0
 * Agent状态信息表-Service实现
 * @author zfsn
 * @date 2023-4-14
 */
@Slf4j
@Service
public class ConfAgentStatusInfoServiceImpl extends ServiceImpl<ConfAgentStatusInfoMapper, ConfAgentStatusInfo>
		implements ConfAgentStatusInfoService {

	@Autowired
	private ConfAgentStatusInfoMapper agentStatusInfoMapper;

	@Lazy
	@Autowired
	private ConfAgentIpService confAgentIpService;



	/**
	 * 保存agent状态信息
	 *
	 * @param apdtos
	 * @param request
	 */

	@Override
	public void handleAgentStatusInfo(AgentStatusInfoDto[] apdtos, HttpServletRequest request) {
		if(apdtos != null) {
			log.info("接收到了 agent信息个数：{}, 开始处理请求", apdtos.length);
		}

		List<AgentStatusInfoDb> dbList = new ArrayList<>();

		for (AgentStatusInfoDto apdto : apdtos) {
			try {
				if (StringUtils.isNotBlank(apdto.getAgentIp())) {
					String probeIp = IpUtils.getIpAddr(request);
					if (StringUtils.isNotBlank(probeIp)) {
						apdto.setProbeIp(probeIp);
					}

					List<AgentInfo> list = apdto.getAgentInfo();
					if (!CollectionUtils.isEmpty(list)) {
						log.info("当前agent:"+apdto.getAgentIp()+"接收到了 agentInfo个数："+list.size());


						SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


						//20200724讨论新加一条规则，同一个agent，不同网口，如果agent重启了，那么所有的网口都标记为rebootFlag=1，
						//重启状态置为1，但不一定是异常，因为还要判断阀值是不是超过，且标记重启agent.setWrongStatus(WrongStatusEnum.RebootCount.getValue());
						int rebootFlag = 0;
						int rebootWrongStatus = 0;

						int i = 1;
						for (AgentInfo agent : list) {

							log.debug("当前 agentInfo信息："+agent.toString());

							AgentStatusInfoPojo asip = new AgentStatusInfoPojo();
							// 把agent基本信息copy
							BeanUtils.copyProperties(apdto, asip);

							// 把AgentInfo复制
							BeanUtils.copyProperties(agent, asip);

							String lastLaunchTime = apdto.getLastLaunchTime();
							if (StringUtils.isNotBlank(lastLaunchTime)) {
								Date lastLaunchDate = sdf.parse(lastLaunchTime);
								asip.setLastLaunchTime(lastLaunchDate);
							}
							String lastUpdateTime = apdto.getLastUpdateTime();
							if (StringUtils.isNotBlank(lastUpdateTime)) {
								Date lastUpdateDate = sdf.parse(lastUpdateTime);
								asip.setLastUpdateTime(lastUpdateDate);
							}
							// 全部初始状态
							asip.setRebootFlag(0);
							asip.setAgentStatus(0);
							asip.setWrongStatus(0);
							asip.setCollectTopStatus(0);
							asip.setWrongTopStatus(0);
							asip.setStatus(0);
							Date now = new Date();
							String nowStr = sdf.format(now);
							asip.setCreateTime(now);

							asip.setUpdateBy("admin");
							asip.setUpdateTime(now);

							asip.setRemoveDiskPartition("");
							asip.setAgentThreshold("");

							// 先从全局的缓存里面根据ip获取agent，如果没有，说明该agent是新的
							boolean isNewAgent = true;
							// 由于别名是前端设置的，要从缓存里面取
							Map<String, AgentIpPojo> agetnMap = AgentConfigManager.agentIpMap;
							if (agetnMap != null && agetnMap.get(asip.getAgentIp()) != null) {
								AgentIpPojo ipPojo = agetnMap.get(asip.getAgentIp());
								asip.setAliasName(ipPojo.getAliasName());

								// 如果从缓存里面发现该Agent被管理员在前端逻辑删除了，那么这里发现又有数据进来，那么激活它
								if (ipPojo.getStatus() == StatusEnum.DELETE.getValue()) {
									// 这里只更新状态
									AgentIpPojo io = new AgentIpPojo();
									io.setAgentIp(ipPojo.getAgentIp());
									io.setStatus(StatusEnum.NORMAL.getValue());
									confAgentIpService.updateByIpSelective(io);
								}

								isNewAgent = false;
							} else {
								// 如果是新的agent保存到表里面
								initAgent(asip);
							}

							// 判断异常
							dealAgentStatusByWrong(asip);

							// 如果不是新的agent才判断重启
							if (!isNewAgent) {
								if(rebootFlag == 1 && rebootWrongStatus == WrongStatusEnum.RebootCount.getValue()) {
									asip.setRebootFlag(StatusEnum.DELETE.getValue());
									asip.setAgentStatus(AgentStatus.WRONG.getValue());
									asip.setWrongStatus(WrongStatusEnum.RebootCount.getValue());
								}else if(rebootFlag == 1){
									//不超阀值
									asip.setRebootFlag(StatusEnum.DELETE.getValue());
								}else {
									dealAgentStatusByReboot(asip);
								}
							}

							//因为同一个agent重启时间是一样的，所以只要第一个判断是重启，而且是异常的，后面不同网口都是同样的标志
							if(i == 1) {
								rebootFlag = asip.getRebootFlag();
								rebootWrongStatus = asip.getWrongStatus();
							}


							// 触发断采统计
							dealAgentStatusByBreakCollection(asip);

							AgentStatusInfoDb db = new AgentStatusInfoDb();
							BeanUtils.copyProperties(asip, db);

							if (StringUtils.isNotBlank(lastLaunchTime)) {
								db.setLastLaunchTimeStr(lastLaunchTime);
							}
							if (StringUtils.isNotBlank(lastUpdateTime)) {
								db.setLastUpdateTimeStr(lastUpdateTime);
							}
							db.setCreateTimeStr(nowStr);
							db.setUpdateTimeStr(nowStr);

							dbList.add(db);

							//标志位加1
							i++ ;
						}
					}
				} else {
					log.error("agentIp为空，接口接收的agent信息：" + apdto.toString());
				}
			} catch (Exception e) {
				log.error("接口接收的agent信息：{}", apdto.toString());
				log.error(StringUtils.exceptionStackToString(e));
			}
		}

		if (dbList.size() > 0) {
			agentStatusInfoMapper.insertAgentStatusInfoBatch(dbList);
		}

		if(apdtos != null) {
			log.info("批量处理入库个数："+ dbList.size() + " , 结束处理请求。");
		}
	}

	/**
	 * 判断异常状态
	 *
	 * @param agent
	 */
	private void dealAgentStatusByWrong(AgentStatusInfoPojo agent) {
		Map<String, AgentThresholdPojo> map = AgentConfigManager.agentThresholdMap;
		if (map != null && map.get(AgentConfigManager.AGENT_COLLECTION_THRESHOLD) != null) {
			AgentThresholdPojo threshold = map.get(AgentConfigManager.AGENT_COLLECTION_THRESHOLD);

			StringBuffer sb = new StringBuffer();
			sb.append("重启次数(次/天):");
			sb.append(threshold.getRebootCount());
			sb.append(" , 丢包率(%):");
			sb.append(threshold.getLostRate());
			sb.append(" , CPU使用率(%):");
			sb.append(threshold.getCpuRate());
			sb.append(" , 内存使用率(%):");
			sb.append(threshold.getMemoryRate());
			sb.append(" , 磁盘使用率(%):");
			sb.append(threshold.getDiskRate());

			agent.setAgentThreshold(sb.toString());

			Map<String, AgentIpPojo> agetnMap = AgentConfigManager.agentIpMap;
			AgentIpPojo agentIp = agetnMap.get(agent.getAgentIp());
			if(agentIp != null && StringUtils.isNotBlank(agentIp.getRemoveDiskPartition())) {
				agent.setRemoveDiskPartition(agentIp.getRemoveDiskPartition());
			}

			// 接口传的值是乘以10000
			Integer cpuRate = threshold.getCpuRate() * 100;
			if (cpuRate <= agent.getCpuRate()) {
				agent.setAgentStatus(AgentStatus.WRONG.getValue());
				agent.setWrongStatus(WrongStatusEnum.CpuRate.getValue());
				return;
			}

			Integer memoryRate = threshold.getMemoryRate() * 100;
			if (memoryRate <= agent.getMemoryRate()) {
				agent.setAgentStatus(AgentStatus.WRONG.getValue());
				agent.setWrongStatus(WrongStatusEnum.MemoryRate.getValue());
				return;
			}

			// 流量为0，即分钟总抓包为020200706和张乐、庄林讨论，拿分钟总抓包总数判断流量为0
            /*20200727杨总监说去掉流量为0的判断if (agent.getMinuteCaptureCount() != null && 0 == agent.getMinuteCaptureCount().intValue()) {
                agent.setAgentStatus(AgentStatus.WRONG.getValue());
                agent.setWrongStatus(WrongStatusEnum.MinuteCaptureZero.getValue());
                return;
            }*/

			Integer lostRate = threshold.getLostRate();
			if (agent.getMinuteCaptureCount() != null && 0 != agent.getMinuteCaptureCount().intValue()
					&& agent.getMinuteCaptureLostCount() != null) {
				//20200820张乐确认   丢包率 = 分钟丢包数  / (分钟抓包数 + 分钟丢包数)
				double minuteRate = agent.getMinuteCaptureLostCount().doubleValue() / (agent.getMinuteCaptureCount().doubleValue() + agent.getMinuteCaptureLostCount().doubleValue())
						* 100;
				if (minuteRate >= lostRate.doubleValue()) {
					agent.setAgentStatus(AgentStatus.WRONG.getValue());
					agent.setWrongStatus(WrongStatusEnum.LostRate.getValue());
					return;
				}
			}

			// 磁盘默认100，没有乘以10000
			Integer diskRate = threshold.getDiskRate();
			if (diskRate <= agent.getDiskRate()) {
				// 特殊逻辑，1、首先判断磁盘占用率大于等于阀值。2、判断管理员是否配置了过滤磁盘分区，如果都完全都匹配，那么不算异常，如果不完全匹配，那么还是算异常(即map还有数据)。
				// 比如：/bak=91%|/root=90%。
				if (agentIp != null && StringUtils.isNotBlank(agentIp.getRemoveDiskPartition())
						&& StringUtils.isNotBlank(agent.getAllDiskInfo())) {
					String[] diskInfos = agent.getAllDiskInfo().split("\\|");
					Map<String, Integer> diskMap = new HashMap<String, Integer>();
					for (String disk : diskInfos) {
						if (StringUtils.isEmpty(disk)) {
							continue;
						}
						// 截取分区名
						String partision = disk.substring(0, disk.indexOf("="));

						// 截取占比
						String rateStr = disk.substring(disk.indexOf("=") + 1, disk.indexOf("%"));
						Integer rate = Integer.parseInt(rateStr);

						// 判断大于阀值的才放到map里面
						if (rate >= threshold.getDiskRate()) {
							diskMap.put(partision, rate);
						}
					}

					if (diskMap.size() > 0) {
						// 从系统启动的缓存里面获取的AgentIpPojo得到过滤的分区
						if (StringUtils.isNotBlank(agentIp.getRemoveDiskPartition())) {
							String[] partitions = agentIp.getRemoveDiskPartition().split("\\|");
							for (String ss : partitions) {
								if (diskMap.get(ss) != null) {
									diskMap.remove(ss);
								}
							}
						}
					}

					if (diskMap.size() > 0) {
						agent.setAgentStatus(AgentStatus.WRONG.getValue());
						agent.setWrongStatus(WrongStatusEnum.DiskRate.getValue());
						return;
					}
				} else {
					// 如果没有配置过滤分区规则，那么超过阀值，直接是异常
					agent.setAgentStatus(AgentStatus.WRONG.getValue());
					agent.setWrongStatus(WrongStatusEnum.DiskRate.getValue());
					return;
				}
			}
		}
	}

	/**
	 * 判断重启(每天多少次) 判断：逻辑就是取之前的最后重启时间判断，当前入库的agent，最后重启时间大于历史agent的时间，就算是重启，小于等于都算正常
	 *  @param agent
	 *
	 */
	private void dealAgentStatusByReboot(AgentStatusInfoPojo agent) {
		Map<String, AgentIpPojo> agetnMap = AgentConfigManager.agentIpMap;
		AgentIpPojo agentIp = agetnMap.get(agent.getAgentIp());
		if (agentIp != null) {
			// 更新缓存中的计算机名
			agentIp.setHostName(agent.getHostName());
		}
		if (agentIp != null && agent.getLastLaunchTime().compareTo(agentIp.getLastLaunchTime()) > 0) {
			//只要时间大于就算一次重启
			agent.setRebootFlag(StatusEnum.DELETE.getValue());

			// 查询阀值，看配置是一天多少次，如果一天一次，那么只要重启就是异常
			boolean isRebootMuch = true;
			Map<String, AgentThresholdPojo> map = AgentConfigManager.agentThresholdMap;
			if (map != null && map.get(AgentConfigManager.AGENT_COLLECTION_THRESHOLD) != null) {
				AgentThresholdPojo threshold = map.get(AgentConfigManager.AGENT_COLLECTION_THRESHOLD);
				Integer rebootNum = threshold.getRebootCount();
				if (rebootNum > 1) {
					Map condition = new HashMap();
					condition.put("agentIp", "'" + agent.getAgentIp() + "'");
					int count = agentStatusInfoMapper.countRebootNumByIp(condition);
					isRebootMuch = (count+1) >= rebootNum ? true : false;
				}
			}

			if (isRebootMuch) {
				agent.setAgentStatus(AgentStatus.WRONG.getValue());
				agent.setWrongStatus(WrongStatusEnum.RebootCount.getValue());
			}

			// 回填最新的重启时间到缓存里面
			agentIp.setLastLaunchTime(agent.getLastLaunchTime());

			AgentIpPojo apo = new AgentIpPojo();
			apo.setAgentIp(agent.getAgentIp());
			apo.setHostName(agent.getHostName());
			apo.setLastLaunchTime(agent.getLastLaunchTime());
			apo.setUpdateTime(new Date());

			confAgentIpService.updateByIpSelective(apo);
		}
	}

	/**
	 * 判断断采 需要增加算法判断1分钟内，某个agent是否断采。(由于探针可能部署多台，同时发送到配置系统，不能保证前后关系)
	 * 需要写算法：初始化一个map，key为年月日时分，value为初始化的Set集合，把正常状态的agent_ip初始化到Set里面，
	 * 接收到数据后，以探针给的“最后更新时间”来判断是哪个key，如果不存在，生成一个key并初始化Set，同时移除对应的agent_ip；
	 * 如果已经存在，把对应的Set里面移除掉该对应的agent_ip。同时判断当前“最后更新时间”减去5分得到的时间，把这个时间之前的数据都统计入库到agent状态信息表。
	 * 比如“最后更新时间”为2020-06-03 19:16:07 那么减去5分， 得到2020-06-03
	 * 19:16:02，那么比这个时间早的都统计入库，同时在map里面移除掉(避免内存溢出)。
	 *
	 * @param agent
	 */
	private void dealAgentStatusByBreakCollection(AgentStatusInfoPojo agent) {
		ConcurrentHashMap<String, Set<String>> timeMap = AgentConfigManager.timeMap;
		Map<String, AgentThresholdPojo> map = AgentConfigManager.agentThresholdMap;
		// 默认5分钟间隔统计断采入库
		Integer collectMinute = 5;
		if (map != null && map.get(AgentConfigManager.AGENT_COLLECTION_THRESHOLD) != null) {
			AgentThresholdPojo threshold = map.get(AgentConfigManager.AGENT_COLLECTION_THRESHOLD);
			if (threshold.getCollectMinute() != null) {
				collectMinute = threshold.getCollectMinute();
			}
		}

		Date before = DateTool.getBeforeMinute(new Date(), collectMinute - 1);
		// 目前是1分钟一次采集频率，系统默认配置5分钟入库统计是否断采，那么为了避免临界值取阀值再减1，即新的数据4分钟前进来，那么不判断是否断采
		// 目前是5分钟一次触发统计入库，会清理timeMap，所以上面建议是减1，比如当前为55分钟，那么小于等于51分的都不判断了。
		if (agent.getLastUpdateTime().compareTo(before) <= 0) {
			return;
		}

		//防止agent 中断的数据采集不到
		Date date = new Date();
		Date lastUpdateTime = agent.getLastUpdateTime();
		while (lastUpdateTime.compareTo(date) < 1){
			String timeStr = DateTool.yyyyMMddHHmm(lastUpdateTime);
			if (!timeMap.containsKey(timeStr)) {
				Set<String> set = new CopyOnWriteArraySet<String>();
				set.addAll(AgentConfigManager.ipSet);
				timeMap.put(timeStr, set);
			}
			lastUpdateTime = DateTool.getAfterMinute(lastUpdateTime, 1);
		}

		if (timeMap.containsKey(agent.getFormatTime())){
			timeMap.get(agent.getFormatTime());
		}else {
			Set<String> set = new CopyOnWriteArraySet<String>();
			set.addAll(AgentConfigManager.ipSet);
			log.debug(agent.getAgentIp() + " -- " + agent.getFormatTime() + "--移除自己前的ipSet:" + set.toString());

			timeMap.put(agent.getFormatTime(), set);
			//删除其他key 包
		}
		timeMap.get(agent.getFormatTime()).remove(agent.getAgentIp());
		log.debug(agent.getAgentIp() + " -- " + agent.getFormatTime() + "--移除自己后的ipSet:" + timeMap.get(agent.getFormatTime()).toString());

		// 有没有找到都开始处理统计入库的操作，以当前时间间隔前5分钟
		Date beforeMinute = DateTool.getBeforeMinute(new Date(), collectMinute);
		String formateDate = DateTool.yyyyMMddHHmm(beforeMinute);
		if (timeMap.size() > 0) {
			dealBreakCollectionToDb(timeMap, formateDate);
			// 触发断采，更新t_agent_ip
			log.info("断采数据统计入库，更新t_agent_ip");
			AgentIpPojo agentIpPojo = new AgentIpPojo();
			BeanUtils.copyProperties(agent, agentIpPojo);
			confAgentIpService.updateByIpSelective(agentIpPojo);
		}

	}


	/**
	 * 只要有数据进来，就触发断采统计入库操作
	 *
	 * @param timeMap
	 * @param formateDate
	 */
	private void dealBreakCollectionToDb(ConcurrentHashMap<String, Set<String>> timeMap, String formateDate) {
		try {
			Long formateDateNum = Long.valueOf(formateDate);
			for (Map.Entry<String, Set<String>> entry : timeMap.entrySet()) {
				String key = entry.getKey();
				Long keyNum = Long.valueOf(key);
				Set<String> set = entry.getValue();


				// map里面的时间比formateDate小的都入库
				if (keyNum < formateDateNum && !CollectionUtils.isEmpty(set)) {
					List<AgentStatusInfoDb> dbList = new ArrayList<AgentStatusInfoDb>();

					log.debug(" -断采入库formatime：" + key + " ，入库的set:" + set.toString());

					String time = key + "00";
					SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
					Date newDate = sdf.parse(time);

					SimpleDateFormat dbSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

					for (String ip : set) {

						Date now = new Date();
						// 断采的数据只要ip、别名、入库时间、断采状态、主机名、formatTime，其他默认0
						AgentStatusInfoDb collection = new AgentStatusInfoDb();
						collection.setAgentIp(ip);
						collection.setFormatTime(key);
						// 由于别名是前端设置的，要从缓存里面取
						Map<String, AgentIpPojo> agetnMap = AgentConfigManager.agentIpMap;
						if (agetnMap != null && agetnMap.get(ip) != null) {
							AgentIpPojo ipPojo = agetnMap.get(ip);
							collection.setAliasName(ipPojo.getAliasName());
							collection.setHostName(ipPojo.getHostName());
						}
						collection.setVersion("");
						collection.setLastLaunchTime(newDate);
						collection.setLastUpdateTime(newDate);

						collection.setEthCount(0);
						collection.setCapturePort("");
						collection.setCaptureSpeed(0);
						collection.setMinuteCaptureCount(0);
						collection.setMinuteCaptureLostCount(0);
						collection.setMinuteQueueLostCount(0);
						collection.setCaptureCount(0L);
						collection.setCaptureLostCount(0L);
						collection.setQueueLostCount(0L);
						collection.setSendSpeed(0);
						collection.setCompressRate(0);
						collection.setCpuRate(0);
						collection.setMemoryRate(0);
						collection.setDiskRate(0);
						collection.setAllDiskInfo("");
						collection.setRebootFlag(0);
						collection.setAgentStatus(AgentStatus.BREAK_COLLECTION.getValue());
						collection.setWrongStatus(0);
						collection.setCollectTopStatus(0);
						collection.setWrongTopStatus(0);

						collection.setRemoveDiskPartition("");
						collection.setAgentThreshold("");

						collection.setCreateTime(now);
						collection.setUpdateBy("admin");
						collection.setUpdateTime(now);
						collection.setStatus(0);
						collection.setRemarks("断采数据");

						collection.setProbeIp("");

						collection.setLastLaunchTimeStr(dbSdf.format(newDate));
						collection.setLastUpdateTimeStr(dbSdf.format(newDate));
						collection.setCreateTimeStr(dbSdf.format(now));
						collection.setUpdateTimeStr(dbSdf.format(now));

						dbList.add(collection);

					}

					if (dbList.size() > 0) {
						agentStatusInfoMapper.insertAgentStatusInfoBatch(dbList);
					}
					// 已经处理入库的，清理掉
					timeMap.remove(key);
				}
			}
		} catch (Exception e) {
			log.error(StringUtils.exceptionStackToString(e));
		}
	}

	private void initAgent(AgentStatusInfoPojo agent) {
		CopyOnWriteArraySet<String> ipSet = AgentConfigManager.ipSet;
		ipSet.add(agent.getAgentIp());

		AgentIpPojo ipPojo = new AgentIpPojo();
		// 把agent基本信息copy
		BeanUtils.copyProperties(agent, ipPojo);
		confAgentIpService.insertAgentIp(ipPojo);

		AgentConfigManager.agentIpMap.put(agent.getAgentIp(), ipPojo);
	}

	/**
	 * 前端删除agent的时候查询十分钟该agent是否有数据，有就不能逻辑删除
	 *
	 * @param map
	 * @return
	 */

	@Override
	public List<ConfAgentStatusInfo> countTenMinuteGroupByIp(Map map) {
		return agentStatusInfoMapper.countTenMinuteGroupByIp(map);
	}

	/**
	 * 统计断采个数、异常个数、正常个数
	 *
	 * @return
	 */

	@Override
	public List<ConfAgentStatusInfo> countByAgentStatus() {
		String zeroToday = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		Map map = new HashMap();
		map.put("zeroToday", zeroToday);
		return agentStatusInfoMapper.countByAgentStatus(map);
	}

	/**
	 * 查询当天该表的信息，按ip分组统计，参数是状态
	 *
	 * @param ap
	 * @return
	 */

	@Override
	public R queryListGroupByIpAndAgentStatus(AgentStatusInfoParams ap) {
		Page<ConfAgentStatusInfo> page = new Page<>(ap.getPageNum(), ap.getPageSize());

		// 对前端传过来的ip处理
		if (StringUtils.isEmpty(ap.getAgentIp())) {
			ap.setAgentIp(null);
		}

		String zeroToday = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		ap.setStartTime(zeroToday);


		Page<ConfAgentStatusInfo> resultlist = agentStatusInfoMapper.queryListGroupByIpAndStatus(page,ap);
		return R.ok(resultlist);
	}


	/**
	 * 查询当天的信息，按ip和状态查询
	 *
	 * @param ap
	 *
	 * @return
	 */

	@Override
	public R queryListByIpAndAgentStatus(AgentStatusInfoParams ap) {
		if(ap == null || StringUtils.isBlank(ap.getAgentIp()) || ap.getAgentStatus() == null) {
			return R.failed("agentIp和agentStatus不能为空");
		}

		String zeroToday = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		Page<ConfAgentStatusInfo> page = new Page<>(ap.getPageNum(), ap.getPageSize());

		Map map = new HashMap();
		map.put("ap", ap);
		map.put("zeroToday", zeroToday);
		Page<ConfAgentStatusInfo> resultlist = agentStatusInfoMapper.queryListByIpAndAgentStatus(page,map);
		return R.failed(resultlist);
	}

	/**
	 * 更新当天的不参加top展示的断采信息
	 *
	 * @param agentIp
	 * @return
	 */

	@Override
	public int updateCollectTopStatusByIp(String agentIp) {
		Map map = new HashMap();
		map.put("agentIp", "'" + agentIp + "'");
		return agentStatusInfoMapper.updateCollectTopStatusByIp(map);
	}

	/**
	 * 前端操作，根据ip过滤掉当前的异常top排名
	 *
	 * @param agentIp
	 * @return
	 */

	@Override
	public int updateWrongTopStatusByIp(String agentIp) {
		Map map = new HashMap();
		map.put("agentIp", "'" + agentIp + "'");
		return agentStatusInfoMapper.updateWrongTopStatusByIp(map);
	}

	/**
	 * 前端获取最新的一个agent详情
	 *
	 * @param ap
	 */

	@Override
	public ConfAgentStatusInfo getAgentDetail(AgentStatusInfoPojo ap) {
		Date now = new Date();
		Map map = new HashMap();
		map.put("ap", ap);

		ConfAgentStatusInfo vo = agentStatusInfoMapper.getAgentDetail(map);

		if (vo == null) {
			Calendar c = Calendar.getInstance();
			c.setTime(now);
			c.add(Calendar.DAY_OF_MONTH, -2);
			Date startTime = c.getTime();

			Map mapH = new HashMap();
			mapH.put("ap", ap);

			vo = agentStatusInfoMapper.getAgentDetailByHistory(mapH);
		}

		return vo;
	}



	/**
	 * 根据ip获取该ip历史启动时间
	 *
	 * @param agentIp
	 */

	@Override
	public List<ConfAgentStatusInfo> rebootHistoryTime(String agentIp) {
		AgentStatusInfoPojo ap = new AgentStatusInfoPojo();
		Map map = new HashMap();
		map.put("agentIp", agentIp);
		List<ConfAgentStatusInfo> list = agentStatusInfoMapper.rebootHistoryTime(map);
		return list;
	}

	/**
	 * 获取探针部署ip
	 *
	 * @param moduleName
	 * @return
	 */

	@Override
	public List<String> getModuleManagement(String moduleName) {
		return agentStatusInfoMapper.getModuleManagement(moduleName);
	}

	/**
	 * 统计agent状态个数
	 *
	 * @return
	 */

	@Override
	public R getAgentCount() {
		ConfAgentStatusInfo vo = new ConfAgentStatusInfo();
		int agentIpCount = confAgentIpService.countNormalAgentIp();
		vo.setAgentIpCount(agentIpCount);

		List<ConfAgentStatusInfo> list = countByAgentStatus();
		if (!CollectionUtils.isEmpty(list)) {
			for (ConfAgentStatusInfo statusVo : list) {
				if (statusVo.getAgentStatus() == AgentStatus.BREAK_COLLECTION.getValue()) {
					vo.setBreakCollectCount(statusVo.getNormalCount());
				} else if (statusVo.getAgentStatus() == AgentStatus.WRONG.getValue()) {
					vo.setWrongCount(statusVo.getNormalCount());
				} else {
					vo.setNormalCount(statusVo.getNormalCount());
				}
			}
		}

		return R.ok(vo);
	}


	/**
	 * 查询断采top数据
	 *
	 * @return
	 */
	@Override
	public R getBreakTop() {

//        Date now = new Date();
//        String tableName = agentTableService.getTodayAgentTable(now);
		String zeroToday = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		Map map = new HashMap();
		map.put("zeroToday", zeroToday);

		List<ConfAgentStatusInfo> list = agentStatusInfoMapper.getBreakTop(map);

		// y轴数组
		List<String> yAxis = new ArrayList<String>();
		List<Long> data = new ArrayList<Long>();

		if (list != null && list.size() > 0) {
			for (ConfAgentStatusInfo agent : list) {
				String ip = agent.getAgentIp();
				yAxis.add(ip);
				if (agent.getBreakCollectCount() != null) {
					data.add(agent.getBreakCollectCount().longValue());
				} else {
					data.add(0L);
				}
			}
		}
		Map<String, Object> rMap = new HashMap<>(2);
		rMap.put("yAxis", yAxis);
		rMap.put("data", data);

		return R.ok(rMap);
	}

	/**
	 * 查询异常top数据
	 *
	 * @return
	 */

	@Override
	public R getWrongTop() {
//        判断表
		String zeroToday = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
		Map map = new HashMap();
		map.put("tableName", "conf_agent_status_info");
		map.put("zeroToday", zeroToday);
		List<ConfAgentStatusInfo> list = agentStatusInfoMapper.getWrongTop(map);
		// y轴数组
		List<String> yAxis = new ArrayList<String>();
		List<Long> data = new ArrayList<Long>();

		if (list != null && list.size() > 0) {
			for (ConfAgentStatusInfo agent : list) {
				String ip = agent.getAgentIp();
				yAxis.add(ip);
				if (agent.getWrongCount() != null) {
					data.add(agent.getWrongCount().longValue());
				} else {
					data.add(0L);
				}
			}
		}

		Map<String, Object> rMap = new HashMap<>(2);
		rMap.put("yAxis", yAxis);
		rMap.put("data", data);

		return R.ok(rMap);
	}

	/**
	 * 丢包率历史曲线图
	 *
	 * @param params
	 * @return
	 */
	@Override
	public R lostHistoryLine(AgentStatusInfoParams params) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date now = new Date();
		Date start = now;
		Date end = now;
		try {
			start = sdf.parse(params.getStartTime());
			end = sdf.parse(params.getEndTime());
		} catch (ParseException e) {
			log.error("startTime:" + params.getStartTime() + " , endTime:" + params.getEndTime());
			log.error(e.getMessage(),e);
			return R.failed("时间不能为空");
		}


		Map mybatisMap = new HashMap();
		mybatisMap.put("agentIp", params.getAgentIp());
		mybatisMap.put("startTime", params.getStartTime());
		mybatisMap.put("endTime", params.getEndTime());
		List<ConfAgentStatusInfo> list = agentStatusInfoMapper.lostHistoryLine(mybatisMap);

		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		LocalDateTime startF = LocalDateTime.parse(params.getStartTime(), formatter);
		LocalDateTime endF = LocalDateTime.parse(params.getEndTime(), formatter);
		// 计算查询时间间隔
		Duration minutesDuration = Duration.between(startF, endF);
		long minutes = minutesDuration.toMinutes();


		SimpleDateFormat dyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		//小于1天(SimpleDateFormat dyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:00");)
		if(minutes <= 1440 ) {
			dyFormat = new SimpleDateFormat("HH:mm");
		}
		// 时间x轴数组
		List<String> timeList = new ArrayList<String>();

		List<String> names = new ArrayList<String>();
		Map<String, List<String>> map = new LinkedHashMap();
		if (list != null && list.size() > 0) {
			for (ConfAgentStatusInfo agent : list) {
				String name = "抓包口" + agent.getCapturePort() + "";

				String luTime = dyFormat.format(agent.getLastUpdateTime());

				//由于探针可能会在一分钟里面发两次，导致数据和时间标签不一致，那么如果同一分钟里面有两次，那么后面的值覆盖前面的
				boolean isExist = true;
				if (!timeList.contains(luTime)) {
					isExist = false;
					timeList.add(luTime);
				}

				Double rate = 0D;
				if (agent.getMinuteCaptureCount() != null && agent.getMinuteCaptureCount() != 0
						&& agent.getMinuteCaptureLostCount() != null) {
					rate = agent.getMinuteCaptureLostCount().doubleValue() / (agent.getMinuteCaptureCount().doubleValue() + agent.getMinuteCaptureLostCount().doubleValue()) * 100;
				}

				List<String> timeVal = map.get(name);
				if (timeVal != null) {
					//由于探针可能会在一分钟里面发两次，导致数据和时间标签不一致，那么如果同一分钟里面有两次，那么后面的值覆盖前面的
					if(isExist && timeVal.size() == timeList.size()) {
						timeVal.remove(timeVal.size() - 1);
					}
					timeVal.add(rate + "");
				} else {
					names.add(name);
					List<String> m = new ArrayList<String>();
					m.add(rate + "");
					map.put(name, m);
				}
			}
		}

		LineChartVo vo = new LineChartVo();
		vo.setTimeList(timeList);
		vo.setLegendList(names);
		List<SubLineChartVo> sbList = new ArrayList<SubLineChartVo>();
		for(String name : names) {
			SubLineChartVo sbvo = new SubLineChartVo();
			sbvo.setName(name);
			sbvo.setData(map.get(name));
			sbList.add(sbvo);
		}
		vo.setSubList(sbList);

		return R.ok(vo);
	}

	/**
	 * 流量历史曲线图
	 *
	 * @param params
	 * @return
	 */
	@Override
	public R speedHistoryLine(AgentStatusInfoParams params) {
		Map mybatisMap = new HashMap();
		mybatisMap.put("agentIp", params.getAgentIp());
		mybatisMap.put("startTime", params.getStartTime());
		mybatisMap.put("endTime", params.getEndTime());

		List<ConfAgentStatusInfo> list = agentStatusInfoMapper.speedHistoryLine(mybatisMap);

		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		LocalDateTime startF = LocalDateTime.parse(params.getStartTime(), formatter);
		LocalDateTime endF = LocalDateTime.parse(params.getEndTime(), formatter);
		// 计算查询时间间隔
		Duration minutesDuration = Duration.between(startF, endF);
		long minutes = minutesDuration.toMinutes();


		SimpleDateFormat dyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		//小于1天(SimpleDateFormat dyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:00");)
		if(minutes <= 1440 ) {
			dyFormat = new SimpleDateFormat("HH:mm");
		}
		// 时间x轴数组
		List<String> timeList = new ArrayList<String>();

		List<String> names = new ArrayList<String>();
		Map<String, List<String>> map = new LinkedHashMap();
		if (list != null && list.size() > 0) {
			for (ConfAgentStatusInfo agent : list) {
				String name = "抓包口" + agent.getCapturePort() + "";
				String luTime = dyFormat.format(agent.getLastUpdateTime());
				//由于探针可能会在一分钟里面发两次，导致数据和时间标签不一致，那么如果同一分钟里面有两次，那么后面的值覆盖前面的
				boolean isExist = true;
				if (!timeList.contains(luTime)) {
					isExist = false;
					timeList.add(luTime);
				}

				Integer speed = agent.getCaptureSpeed();

				List<String> timeVal = map.get(name);
				if (timeVal != null) {
					//由于探针可能会在一分钟里面发两次，导致数据和时间标签不一致，那么如果同一分钟里面有两次，那么后面的值覆盖前面的
					if(isExist && timeVal.size() == timeList.size()) {
						timeVal.remove(timeVal.size() - 1);
					}
					timeVal.add(speed + "");
				} else {
					names.add(name);
					List<String> m = new ArrayList<String>();
					m.add(speed + "");
					map.put(name, m);
				}
			}
		}
		LineChartVo vo = new LineChartVo();
		vo.setTimeList(timeList);
		vo.setLegendList(names);
		List<SubLineChartVo> sbList = new ArrayList<SubLineChartVo>();
		for(String name : names) {
			SubLineChartVo sbvo = new SubLineChartVo();
			sbvo.setName(name);
			sbvo.setData(map.get(name));
			sbList.add(sbvo);
		}
		vo.setSubList(sbList);

		return R.ok(vo);
	}

	/**
	 * 根据条件查询
	 *
	 * @param searchKey
	 * @return
	 */
	@Override
	public List<ConfAgentIp> queryList(String searchKey) {
		return confAgentIpService.queryList(searchKey);
	}

}